package pers.tong.weiliao.util;

import java.io.*;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.text.DecimalFormat;
import java.util.HashMap;

/**
 * <p>
 * 描述：有关文件信息和操作的工具类
 * 1. 通过文件头判断文件类型
 * 2. 获取格式化的文件大小
 * 3. 高效地将文件转化为字节数组
 * </p>
 */
public class FileUtils {

    public static final HashMap<String, String> fileTypes = new HashMap<>();
    private static final String B_UNIT = "B";
    private static final String KB_UNIT = "KB";
    private static final String MB_UNIT = "MB";
    private static final String GB_UNIT = "GB";
    private static final DecimalFormat decimalFormat;

    static { // BOM (Byte Order Mark) 文件头字节
        fileTypes.put("494433", "mp3");
        fileTypes.put("524946", "wav");
        fileTypes.put("ffd8ff", "jpg");
        fileTypes.put("FFD8FF", "jpg");
        fileTypes.put("89504E", "png");
        fileTypes.put("89504e", "png");
        fileTypes.put("474946", "gif");
        decimalFormat = new DecimalFormat("#.0");
    }

    /**
     * <p>
     * 描述：通过含BOM (Byte Order Mark) 的文件头
     * 的前三个字节判断文件类型
     * </p>
     *
     * @param filePath 文件路径
     * @return
     */
    public static String getFileType(String filePath) {
        return fileTypes.get(getFileHeader3(filePath));
    }

    /**
     * <p>
     * 描述：获取文件头前三个字节
     * </p>
     *
     * @param filePath 文件路劲
     * @return
     */
    private static String getFileHeader3(String filePath) {
        File file = new File(filePath);
        if (file.exists() && file.length() >= 4L) {

            FileInputStream is = null;
            String value = null;

            try {
                is = new FileInputStream(file);
                byte[] b = new byte[3];
                is.read(b, 0, b.length);
                value = bytesToHexString(b);
            } catch (Exception e) {
            } finally {
                if (null != is) {
                    try {
                        is.close();
                    } catch (IOException e) {
                    }
                }
            }

            return value;
        } else {
            return null;
        }
    }

    private static String bytesToHexString(byte[] src) {
        StringBuffer stringBuffer = new StringBuffer();
        if (src != null && src.length > 0) {
            for (int i = 0; i < src.length; ++i) {
                int v = src[i] & 255;
                String hv = Integer.toHexString(v);
                if (hv.length() < 2) {
                    stringBuffer.append(0);
                }
                stringBuffer.append(hv);
            }

            return stringBuffer.toString();
        } else {
            return null;
        }
    }

    /**
     * <p>
     * 描述：获取格式化的文件大小
     * 格式化为带单位保留一位小数
     * </p>
     *
     * @param size
     * @return
     */
    private static String getFormatSize(double size) {
        String fileSizeString = "";
        if (size < 1024.0D) {
            fileSizeString = decimalFormat.format(size) + B_UNIT;
        } else if (size < 1048576.0D) {
            fileSizeString = decimalFormat.format(size / 1024.0D) + KB_UNIT;
        } else if (size < 1073741824.0D) {
            fileSizeString = decimalFormat.format(size / 1048576.0D) + MB_UNIT;
        } else {
            fileSizeString = decimalFormat.format(size / 1073741824.0D) + GB_UNIT;
        }

        return fileSizeString;
    }

    public static String getFormatSize(long size) {
        return getFormatSize((double) size);
    }

    /**
     * <p>
     * 描述：高效率地将文件转换为字节数组
     * </p>
     *
     * @param filePath
     * @return
     */
    @SuppressWarnings("resource")
    public static byte[] toByteArray(String filePath) throws IOException {
        FileChannel fc = null;
        byte[] result;
        try {
            fc = new RandomAccessFile(filePath, "r").getChannel();
            MappedByteBuffer byteBuffer = fc.map(FileChannel.MapMode.READ_ONLY,
                    0L, fc.size()).load();
            System.out.println(byteBuffer.isLoaded());
            byte[] b = new byte[(int) fc.size()];
            if (byteBuffer.remaining() > 0) {
                byteBuffer.get(b, 0, byteBuffer.remaining());
            }

            result = b;
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            try {
                fc.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return result;
    }

    public static void main(String[] args) {
        String filePath = "/home/tong/CloudMusic/Famishin,Angel Note - 恋ひ恋ふ縁＜Piano Version＞.mp3";
        String fileType = FileUtils.getFileType(filePath);
        System.out.println(fileType);
    }
}
